package cn.good.yan.controller;

import cn.good.yan.pojo.Bill;
import cn.good.yan.pojo.CommonResult;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * 演示： （整合openFeign + fallback）
 *     分别启动：9001 9002服务 、84服务
 *     演示1: - 第1种情况
 *          访问：http://localhost:84/t1/fallback/2   自动负载均衡，请求9001 9002服务
 *          访问：http://localhost:84/t1/fallback/4   出现异常 - IllegalArgumentException
 *          访问：http://localhost:84/t1/fallback/5   出现异常 - NullPointerException
 *     演示2：- 第2种情况
 *          访问：http://localhost:84/t1/fallback/2   自动负载均衡，请求9001 9002服务
 *          访问：http://localhost:84/t1/fallback/4   出现异常 - 进入熔断方法：handlerFallT1
 *          访问：http://localhost:84/t1/fallback/5   出现异常 - 进入熔断方法：handlerFallT1
 *     演示3：- 第3种情况
 *          需要配置Sentinel （fallback）流控，AQS阈值限制在1
 *          访问：http://localhost:84/t1/fallback/2   自动负载均衡，请求9001 9002服务，如果AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/4   出现异常 - IllegalArgumentException - AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/5   出现异常 - NullPointerException  - AQS达到2以上，会进入 blockHandler 方法
 *     演示4：- 第4种情况
 *          需要配置Sentinel （fallback）流控，AQS阈值限制在1
 *          访问：http://localhost:84/t1/fallback/2   自动负载均衡，请求9001 9002服务，如果AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/4   出现异常 - 进入熔断方法：handlerFallT1 - AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/5  出现异常 - 进入熔断方法：handlerFallT1  - AQS达到2以上，会进入 blockHandler 方法
 *     演示5：- 第5种情况
 *          需要配置Sentinel （fallback）流控，AQS阈值限制在1
 *          访问：http://localhost:84/t1/fallback/2   自动负载均衡，请求9001 9002服务，如果AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/4   出现异常 - IllegalArgumentException  - AQS达到2以上，会进入 blockHandler 方法
 *          访问：http://localhost:84/t1/fallback/5   出现异常 - 进入熔断方法：handlerFallT1  - AQS达到2以上，会进入 blockHandler 方法
 * @author shengren.yan
 * @create 2024-02-03
 */
@RestController
@RequestMapping("/t1")
@Slf4j
public class T1Controller {

    // 服务器的 - 服务地址
    public static final String SERVICE_URL = "http://nacos-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/fallback/{id}")
    // 第1种情况，没有配置 （请求该地址，会出现异常）
//    @SentinelResource(value = "fallback")
    // 第2种情况，只配置java程序里的异常（请求该地址，http://localhost:84/xxxx/fallback/4） 会出现异常  IllegalArgumentException异常
    //                                          http://localhost:84/xxxx/fallback/4444） 会出现异常  NullPointerException异常
//     @SentinelResource(value = "fallback", fallback = "handlerFallT1")
    // 第3种情况，配置sentinel上的熔断配置 （只配置该配置，不配置 fallback 的第2中方法，此时请求：
    //                                          http://localhost:84/xxxx/fallback/4） 会出现异常，也会返回给页面，如果被限流熔断，会执行该blockHandler方法里的逻辑
    //                                          ）
//      @SentinelResource(value = "fallback", blockHandler = "blockHandler")
    // 第4种情况，如果全配置，如果有java异常，会执行该handlerFallT1方法里逻辑
    //                     如果有限流熔断的，会执行该blockHandler方法里逻辑
    //                     如果都满足的情况的下，会执行该blockHandler方法里逻辑
//     @SentinelResource(value = "fallback", fallback = "handlerFallT1", blockHandler = "blockHandler")
    // 第5种情况，exceptionsToIgnore：忽略属性，如果触发限流熔断，不会进行拦截
     @SentinelResource(value = "fallback", fallback = "handlerFallT1", blockHandler = "blockHandler",
     exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Bill> fallback(@PathVariable Long id) {
        CommonResult<Bill> result = restTemplate.getForObject(SERVICE_URL + "/t2/one/" + id, CommonResult.class, id);

        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    public CommonResult<Bill> handlerFallT1(@PathVariable Long id, Throwable e) {
        Bill bill = new Bill(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallT1异常  " + e.getMessage(), bill);
    }

    public CommonResult<Bill>  blockHandler(@PathVariable Long id, BlockException blockException) {
        Bill bill = new Bill(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流  " + blockException.getMessage(), bill);
    }





}
